<script setup lang="ts">
interface MsgList {
  id: number
  type: 'error' | 'success' | ''
  msg: string | Msg | VNode
  stop: boolean
}
interface Msg {
  title: string
  content: string | VNode
}
defineOptions({
  name: 'BaseNotify',
})
const msgList = ref<MsgList[]>([])
const target = useTemplateRef('target')
const map = new Map()
const count = ref(0)

async function addMsg(msg: string | Msg | VNode, type: 'error' | 'success' | '') {
  if (msgList.value.length > 0) {
    return new Promise<void>((resolve) => {
      moveOut(count.value)
      resolve()
    })
      .then(async () => {
        await removeMsg(count.value)
        count.value++

        const list = { id: count.value, type, msg, stop: false }
        msgList.value.push(list)
        await nextTick()
        const currentTar = target.value?.[target.value.length - 1]
        moveIn(currentTar as HTMLDivElement)
        if (target.value) {
          map.set(count.value, currentTar)
        }
      })
  }
  else {
    count.value++
    const list: MsgList = { id: count.value, type, msg, stop: false }
    msgList.value.push(list)
    await nextTick()
    const currentTar = target.value?.[target.value.length - 1]
    moveIn(currentTar as HTMLDivElement)
    if (target.value) {
      map.set(count.value, currentTar)
    }
  }
}
async function removeMsg(id: number) {
  setTimeout(() => {
    msgList.value = msgList.value.filter(item => item.id !== id)
    map.delete(id)
  }, 500)
}
function moveIn(el: HTMLDivElement) {
  if (el) {
    const height = el?.offsetHeight || 0
    el.style.height = '0px'

    // eslint-disable-next-line ts/no-unused-expressions
    el.offsetHeight
    el.style.transition = 'height 0.5s'
    el.style.height = `${height}px`
  }
}
function moveOut(id: number) {
  const el = map.get(id)
  if (el) {
    el.style.transition = 'height 0.5s'
    el.style.height = '0px'
    el.style.zIndex = 2
  }
}

function onSvgEnd(v: number) {
  moveOut(v)
}

function onClick(v: number) {
  const el = document.querySelector('.circle-countdown') as SVGElement
  const point = msgList.value.filter(item => item.id == v)
  point[0].stop = !point[0].stop
  if (point[0].stop) {
    el.style.animationPlayState = 'paused'
  }
  else {
    el.style.animationPlayState = 'running'
  }
}

function RenderContent({ msg }: { msg: Msg }) {
  const { title, content } = msg
  const titleVNode = h('h4', null, title)
  const contentVNode = h('p', null, content)
  return h('div', { class: 'break-all leading-[1.5]' }, [
    titleVNode,
    contentVNode,
  ])
}
defineExpose({ addMsg })
</script>

<template>
  <div>
    <div class="toast-notice-wrapper">
      <div
        v-for="{ msg, id, type, stop } of msgList" ref="target" :key="id" class="overflow-hidden flex w-full"
        @click="onClick(id)"
      >
        <div class="toast flex">
          <BaseIcon v-if="type" :name="`notice-${type}`" class="text-xl w-5 h-5 mr-2 flex-none " />
          <!-- 普通字符串 -->
          <div v-if="typeof msg === 'string'" class="break-all max-w-[80%] leading-[1.5]">
            {{ msg }}
          </div>
          <!--  -->

          <!-- 支持content自定义 -->
          <template v-else-if="typeof msg === 'object'">
            <RenderContent :msg="(msg as Msg)" />
          </template>
          <!--  -->
          <div class="ml-auto relative size-5" :class="{ 'opacity-0': stop }">
            <div class="ml-auto size-5">
              <svg class="circle-countdown w-5 h-5 flex-none" viewBox="0 0 32 32" @animationend="onSvgEnd(id)">
                <circle cx="16" cy="16" r="8" />
              </svg>
            </div>
          </div>
          <div v-show="stop" class="ml-auto relative size-5 center" @click.stop="onSvgEnd(id)">
            <BaseIcon name="uni-close" class="text-base" />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style>
:root {
  --bg-base-notify-stroke-color: #24ee89;
}
</style>

<style scoped lang="scss">
.toast {
  flex: 1;
  display: flex;
  align-self: end;
  border-radius: 0.75rem;
  padding: 0.625rem 0.4375rem;
  color: rgb(var(--color-text-white-0));
  background: var(--color-bg-black-2);
  // -webkit-backdrop-filter: blur(5rem);
  // backdrop-filter: blur(5rem);
  margin: 0.25rem;
  box-shadow: 0 0 0.25rem #0000001a;
  z-index: 10;
  font-size: 0.75rem;

}

.toast-notice-wrapper {
  position: fixed;
  left: 1rem;
  right: 1rem;
  top: 1rem;
  z-index: 10000;
}

.circle-countdown {
  fill: none;
  stroke-width: 0.20rem;
  stroke-dasharray: 50.265;
  // stroke-dashoffset: 50.265;
  stroke: var(--bg-base-notify-stroke-color);
  transform: scaleX(-1) rotate(-90deg);
  animation: stroke-down 6s forwards;
  animation-play-state: running;
}

@keyframes stroke-down {
  from {
    stroke-dashoffset: 50.265;
  }

  to {
    stroke-dashoffset: 0;
  }
}
</style>
